﻿using System;
using HK.Core.Common.Protocol.Data;
using HK.Core.Utils;
using HK.Editor.GUIEx.TreeView.Data;
using HK.Editor.Load.Protocol.Data;
using UnityEngine;

namespace HK.Editor.Load.Data
{
    /// <summary>
    /// 加载分支信息
    /// </summary>
    [Serializable]
    public class LoadBranch : TreeBranch<LoadBranch>, ILoadBranch, IEquatable<LoadBranch>
    {
        /// <summary>
        /// 缓存池全局标识Guid
        /// <para>* -1:无效</para>
        /// </summary>
        public long PoolId { get; set; } = -1;
        
        /// <summary>
        /// Name
        /// </summary>
        public override string Name
        {
            get => IsCaller ? caller : AssetKey;
            set
            {
                if (IsCaller)
                {
                    Caller = value;
                    return;
                }
                AssetKey = value;
            }
        }
        
        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => $"{Id}_{AssetKey}";

        [SerializeField]
        private string assetKey = null;
        /// <summary>
        /// AssetKey
        /// <para>* 不包含后缀名</para>
        /// </summary>
        public string AssetKey
        {
            get => assetKey;
            internal set => assetKey = value;
        }

        [SerializeField]
        private AssetFileType assetType = AssetFileType.Unknown;
        /// <summary>
        /// 资产类型
        /// </summary>
        public AssetFileType AssetType 
        {
            get => assetType;
            internal set => assetType = value;
        }

        [SerializeField]
        private string extension = null;
        /// <summary>
        /// 文件后缀
        /// </summary>
        public string Extension 
        {
            get => extension;
            internal set => extension = value;
        }
        
        [SerializeField]
        private string from = null;
        /// <summary>
        /// 加载源
        /// </summary>
        public string From 
        {
            get => from;
            internal set => from = value;
        }
        
        [SerializeField]
        private bool async = false;
        /// <summary>
        /// 异步标志位
        /// <para>* true : 异步; false : 同步;</para>
        /// </summary>
        public bool Async 
        {
            get => async;
            internal set => async = value;
        }
        
        [SerializeField]
        private long size = 0L;
        /// <summary>
        /// 文件大小
        /// <para> * 文件的物理大小。单位:Byte</para>
        /// </summary>
        public long Size 
        {
            get => size;
            internal set => size = value;
        }
        
        [SerializeField]
        private long memorySize = 0L;
        /// <summary>
        /// 内存占用大小
        /// <para> * 文件加载的内存消耗。单位:Byte</para>
        /// </summary>
        public long MemorySize 
        {
            get => memorySize;
            internal set => memorySize = value;
        }
        
        [SerializeField]
        private int referenceCount = 0;
        /// <summary>
        /// 引用计数
        /// </summary>
        public int ReferenceCount 
        {
            get => referenceCount;
            internal set => referenceCount = value;
        }
        
        [SerializeField]
        private float coolTime = 0.0f;
        /// <summary>
        /// 冷却时间
        /// <para>* 倒计时释放的对象的冷却时间(单位:秒)</para>
        /// </summary>
        public float CoolTime 
        {
            get => coolTime;
            internal set => coolTime = value;
        }
        
        [SerializeField]
        private long costTime = 0L;
        /// <summary>
        /// 加载耗时
        /// </summary>
        public long CostTime 
        {
            get => costTime;
            internal set => costTime = value;
        }
        
        [SerializeField]
        private long loadTime = 0L;
        /// <summary>
        /// 加载时间
        /// </summary>
        public long LoadTime 
        {
            get => loadTime;
            internal set => loadTime = value;
        }
        
#region Caller

        [SerializeField]
        private string caller = null;
        /// <summary>
        /// 调用处
        /// </summary>
        public string Caller 
        {
            get => caller;
            internal set => caller = value;
        }

        /// <summary>
        /// 是否为调用信息
        /// </summary>
        public bool IsCaller => !string.IsNullOrEmpty(caller);

#endregion

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid
        {
            get
            {
                if (IsRoot) return true;
                return !string.IsNullOrEmpty(assetKey);
            }
        }

        #region Equals
        
        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iOther">Other</param>
        /// <returns>true:相同; false:不相同;</returns>
        public bool Equals(LoadBranch iOther)
        {
            if (null == iOther || !iOther.Valid) return false;
            if (Id != iOther.Id) return false;
            if (Depth != iOther.Depth) return false;
            if (UtilsString.Diff(assetKey, iOther.AssetKey)) return false;
            if (UtilsString.Diff(extension, iOther.Extension)) return false;
            if (UtilsString.Diff(from, iOther.From)) return false;
            if (async != iOther.Async) return false;
            if (UtilsString.Diff(caller, iOther.Caller)) return false;
            return true;
        }

#endregion

        /// <summary>
        /// 更新值
        /// </summary>
        /// <param name="iCurValue">当前值</param>
        /// <param name="iDstValue">目标值</param>
        /// <param name="iImport">导入标志位</param>
        /// <returns>可以更新的值</returns>
        private AssetFileType UpdateValue(AssetFileType iCurValue, AssetFileType iDstValue, bool iImport)
        {
            var dirty = iCurValue != iDstValue;
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            return dirty ? iDstValue : iCurValue;
        }   

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is ILoadBranch branch)
            {
                assetKey = UpdateValue(assetKey, branch.AssetKey, iImport);
                assetType = UpdateValue(assetType, branch.AssetType, iImport);
                extension = UpdateValue(extension, branch.Extension, iImport);
                from = UpdateValue(from, branch.From, iImport);
                async = UpdateValue(async, branch.Async, iImport);
                size = UpdateValue(size, branch.Size, iImport);
                memorySize = UpdateValue(memorySize, branch.MemorySize, iImport);
                referenceCount = UpdateValue(referenceCount, branch.ReferenceCount, iImport);
                coolTime = UpdateValue(coolTime, branch.CoolTime, iImport);
                costTime = UpdateValue(costTime, branch.CostTime, iImport);
                loadTime = UpdateValue(loadTime, branch.LoadTime, iImport);
                caller = UpdateValue(caller, branch.Caller, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();

            assetKey = null;
            AssetType = AssetFileType.Unknown;
            extension = null;
            from = null;
            async = false;
            size = 0L;
            memorySize = 0L;
            referenceCount = 0;
            coolTime = 0.0f;
            costTime = 0L;
            loadTime = 0L;
            
            caller = null;
        }
    }
}
